package com.jiao.table.listener;

import cn.hutool.core.collection.CollectionUtil;
import com.jiao.comm.entity.QueryContent;
import com.jiao.comm.exception.CloseLoopException;
import com.jiao.comm.exception.ListenerException;
import com.jiao.comm.utils.JDBCUtils;
import com.jiao.datasource.parse.SQLCommand;
import com.jiao.datasource.parse.SQLParse;
import com.jiao.datasource.parse.SQLStruct;
import com.jiao.table.cache.DynamicCacheRead;
import com.jiao.table.cache.DynamicCacheWrite;
import com.jiao.table.config.CacheDataLoad;
import com.jiao.table.entity.TableInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 插入监听器.
 * 当插入前查询最大id, 然后获取所有 colunm>id 的数据集合。然后这些数据全部存放到缓存.
 * @Author Vincent.jiao
 * @Date 2022/5/13 16:59
 */
@Component
public class InsertSQLListener extends WriteSQLListenerAbstract {
    private Map<SQLCommand, Long> rowIdMap = new ConcurrentHashMap<>();

    @Autowired
    DynamicCacheWrite cacheWrite;

    @Autowired
    DynamicCacheRead cacheRead;

    /**
     * 插入前.
     * @param commandInfo
     */
    @Override
    public void execBefore(SQLCommand commandInfo) {
        if(!isInsert(commandInfo)) {
            return;
        }

        if(!isExceCloseLoop(commandInfo)) {
            return;
        }

        TableInfo tableInfo = CacheDataLoad.getTableInfo(commandInfo.getTableName());
        String maxIdSql = SQLStruct.SELECT + " MAX(" + tableInfo.getPrimaryKeyName() + " ) "
                + SQLStruct.FROM + " " + commandInfo.getTableName();

        try {
            Long maxId = JDBCUtils.select(commandInfo.getSqlUnit().getConnection(), maxIdSql, new QueryContent<Long>() {
                @Override
                public Long exectu(ResultSet rs) throws SQLException {
                    while (rs.next()){
                        return rs.getLong(1);
                    }

                    return null;
                }
            });

            if(maxId != null) {
                rowIdMap.put(commandInfo, maxId);
            }

        } catch (Exception e) {
            throw new CloseLoopException(e.getMessage(), e);
        }
    }

    @Override
    public void execAfter(SQLCommand commandInfo) {
        if(commandInfo.getSqlUnit().isAutoCommit()) {
            //如果自动提交就触发闭环
            insertCache(Arrays.asList(commandInfo));
        }
    }

    @Override
    public void commiteAfter(List<SQLCommand> sqlCommands) throws CloseLoopException {
        insertCache(sqlCommands);
    }

    public void insertCache(List<SQLCommand> sqlCommands) {
        List<SQLCommand> insertCommandList = new LinkedList<>();
        for (SQLCommand item : sqlCommands){
            if(!isInsert(item) || !isExceCloseLoop(item)) {
                continue;
            }
            insertCommandList.add(item);
        }

        if(CollectionUtil.isEmpty(insertCommandList)) {
            return;
        }

        for (SQLCommand item : insertCommandList){
            //获取到所有新增的id
            Long maxId = rowIdMap.get(item);
            List<Long> ids = getGtMaxIdList(item, maxId);
            List<Object> datas = getDataById(item, ids);
            cacheWrite.addBatch(datas);
        }
    }

    private List<Long> getGtMaxIdList(SQLCommand sqlCommand, Long maxId) {
        Connection conn = sqlCommand.getSqlUnit().getConnection();
        String sql = getGtMaxIdSql(sqlCommand);
        try {
            return JDBCUtils.select(conn, sql, new QueryContent<List<Long>>() {
                @Override
                public List<Long> exectu(ResultSet rs) throws SQLException {
                    List<Long> ids = new LinkedList<>();

                    while (rs.next()){
                        ids.add(rs.getLong(1));
                    }

                    return ids;
                }
            }, maxId);
        } catch (SQLException e) {
            throw new CloseLoopException(e.getMessage(), e);
        }
    }

    private String getGtMaxIdSql(SQLCommand sqlCommand) {
        TableInfo tableInfo = CacheDataLoad.getTableInfo(sqlCommand.getTableName());

        return SQLStruct.SELECT + " " + tableInfo.getPrimaryKeyName() + " "
                + SQLStruct.FROM + " " + sqlCommand.getTableName() + " "
                + SQLStruct.WHERE + " " +  tableInfo.getPrimaryKeyName() + " > ?";
    }
}
